#include <math.h>
#include <limits.h>
#include <stdlib.h>
#include <float.h>
#include "wtk_json.h"

wtk_json_t* wtk_json_new()
{
	wtk_json_t *json;

	json=(wtk_json_t*)wtk_malloc(sizeof(wtk_json_t));
	json->heap=wtk_heap_new(4096);
	wtk_json_reset(json);
	return json;
}

void wtk_json_delete(wtk_json_t *json)
{
	wtk_heap_delete(json->heap);
	wtk_free(json);
}

void wtk_json_reset(wtk_json_t *json)
{
	wtk_heap_reset(json->heap);
	json->main=0;
}

wtk_json_item_t* wtk_json_new_item(wtk_json_t *json,wtk_json_item_type_t type)
{
	wtk_json_item_t *item;

	item=(wtk_json_item_t*)wtk_heap_malloc(json->heap,sizeof(wtk_json_item_t));
	item->type=type;
	return item;
}

wtk_json_item_t* wtk_json_new_number(wtk_json_t *json,double v)
{
	wtk_heap_t *heap=json->heap;
	wtk_json_item_t *item;

	item=(wtk_json_item_t*)wtk_heap_malloc(heap,sizeof(wtk_json_item_t));
	item->type=WTK_JSON_NUMBER;
	item->v.number=v;
	return item;
}

wtk_json_item_t* wtk_json_new_string(wtk_json_t *json,char *data,int len)
{
	wtk_heap_t *heap=json->heap;
	wtk_json_item_t *item;

	item=(wtk_json_item_t*)wtk_heap_malloc(heap,sizeof(wtk_json_item_t));
	item->type=WTK_JSON_STRING;
	item->v.str=wtk_heap_dup_string(heap,data,len);
	return item;
}

wtk_json_item_t* wtk_json_new_array(wtk_json_t *json)
{
	wtk_heap_t *heap=json->heap;
	wtk_json_item_t *item;

	item=(wtk_json_item_t*)wtk_heap_malloc(heap,sizeof(wtk_json_item_t));
	item->type=WTK_JSON_ARRAY;
	item->v.object=(wtk_queue_t*)wtk_heap_malloc(heap,sizeof(wtk_queue_t));
	wtk_queue_init((item->v.array));
	return item;
}

wtk_json_item_t* wtk_json_new_object(wtk_json_t *json)
{
	wtk_heap_t *heap=json->heap;
	wtk_json_item_t *item;

	item=(wtk_json_item_t*)wtk_heap_malloc(heap,sizeof(wtk_json_item_t));
	item->type=WTK_JSON_OBJECT;
	item->v.object=(wtk_queue_t*)wtk_heap_malloc(heap,sizeof(wtk_queue_t));
	wtk_queue_init((item->v.object));
	return item;
}

wtk_json_item_t* wtk_json_obj_get(wtk_json_item_t *obj,char *key,int key_bytes)
{
	wtk_queue_node_t *qn;
	wtk_json_obj_item_t *item;

	for(qn=obj->v.object->pop;qn;qn=qn->next)
	{
		item=data_offset(qn,wtk_json_obj_item_t,q_n);
		if(wtk_string_cmp(&(item->k),key,key_bytes)==0)
		{
			return item->item;
		}
	}
	return NULL;
}


wtk_json_obj_item_t* wtk_json_new_obj_item(wtk_json_t *json,char *key,int key_bytes,wtk_json_item_t *item)
{
	wtk_json_obj_item_t *x;

	x=(wtk_json_obj_item_t*)wtk_heap_malloc(json->heap,sizeof(wtk_json_obj_item_t));
	wtk_heap_fill_string(json->heap,&(x->k),key,key_bytes);
	x->item=item;
	return x;
}

void wtk_json_obj_add_item(wtk_json_t *json,wtk_json_item_t *obj,wtk_json_obj_item_t *item)
{
	wtk_queue_push(obj->v.object,&(item->q_n));
}

void wtk_json_obj_add_item2(wtk_json_t *json,wtk_json_item_t *obj,char *key,int key_bytes,wtk_json_item_t *item)
{
	wtk_json_obj_item_t *x;

	x=wtk_json_new_obj_item(json,key,key_bytes,item);
	wtk_json_obj_add_item(json,obj,x);
}

void wtk_json_obj_add_ref_str(wtk_json_t *json,wtk_json_item_t *obj,char *key,int key_len,wtk_string_t *v)
{
	wtk_json_item_t *item;
	wtk_json_obj_item_t *x;

	item=wtk_json_new_item(json,WTK_JSON_STRING);
	item->v.str=v;
	x=(wtk_json_obj_item_t*)wtk_heap_malloc(json->heap,sizeof(wtk_json_obj_item_t));
	x->item=item;
	wtk_string_set(&(x->k),key,key_len);
	wtk_json_obj_add_item(json,obj,x);
}

void wtk_json_obj_add_str(wtk_json_t *json,wtk_json_item_t *obj,char *key,int key_len,wtk_string_t *v)
{
	v=wtk_heap_dup_string(json->heap,v->data,v->len);
	wtk_json_obj_add_ref_str(json,obj,key,key_len,v);
}

void wtk_json_obj_add_ref_number(wtk_json_t *json,wtk_json_item_t *obj,char *key,int key_len,double number)
{
	wtk_json_item_t *item;
	wtk_json_obj_item_t *x;

	item=wtk_json_new_item(json,WTK_JSON_NUMBER);
	item->v.number=number;
	x=(wtk_json_obj_item_t*)wtk_heap_malloc(json->heap,sizeof(wtk_json_obj_item_t));
	x->item=item;
	wtk_string_set(&(x->k),key,key_len);
	wtk_json_obj_add_item(json,obj,x);
}


void wtk_json_obj_set_last_item_value(wtk_json_t *json,wtk_json_item_t *obj,wtk_json_item_t *item)
{
	wtk_json_obj_item_t *x;

	x=data_offset(obj->v.object->push,wtk_json_obj_item_t,q_n);
	x->item=item;
}

void wtk_json_array_add_item(wtk_json_t *json,wtk_json_item_t *array,wtk_json_item_t *item)
{
	wtk_json_array_item_t *x;

	x=(wtk_json_array_item_t*)wtk_heap_malloc(json->heap,sizeof(wtk_json_array_item_t));
	x->item=item;
	wtk_queue_push(array->v.array,&(x->q_n));
}

void wtk_json_array_add_ref_str(wtk_json_t *json,wtk_json_item_t *array,wtk_string_t *v)
{
	wtk_json_item_t *item;
	wtk_json_array_item_t *x;

	item=wtk_json_new_item(json,WTK_JSON_STRING);
	item->v.str=v;
	x=(wtk_json_array_item_t*)wtk_heap_malloc(json->heap,sizeof(wtk_json_array_item_t));
	x->item=item;
	wtk_queue_push(array->v.array,&(x->q_n));
}

void wtk_json_array_add_ref_number(wtk_json_t *json,wtk_json_item_t *array,double v)
{
	wtk_json_item_t *item;
	wtk_json_array_item_t *x;

	item=wtk_json_new_item(json,WTK_JSON_NUMBER);
	item->v.number=v;
	x=(wtk_json_array_item_t*)wtk_heap_malloc(json->heap,sizeof(wtk_json_array_item_t));
	x->item=item;
	wtk_queue_push(array->v.array,&(x->q_n));
}

wtk_json_item_t* wtk_json_array_get(wtk_json_item_t* item,int idx)
{
	wtk_queue_node_t *qn;
	wtk_json_array_item_t *ai;

	qn=wtk_queue_peek(item->v.array,idx);
	wtk_debug("v[%d]=%p\n",idx,qn);
	if(!qn){return NULL;}
	ai=data_offset2(qn,wtk_json_array_item_t,q_n);
	return ai->item;
}

void wtk_json_item_print2(wtk_json_item_t *item,wtk_strbuf_t *buf)
{
	wtk_queue_node_t *n;

	switch(item->type)
	{
	case WTK_JSON_FALSE:
		wtk_strbuf_push_s(buf,"false");
		break;
	case WTK_JSON_TRUE:
		wtk_strbuf_push_s(buf,"true");
		break;
	case WTK_JSON_NULL:
		wtk_strbuf_push_s(buf,"null");
		break;
	case WTK_JSON_STRING:
		wtk_strbuf_push_c(buf,'\"');
		if(item->v.str)
		{
			// wtk_strbuf_push_add_escape_str(buf,item->v.str->data,item->v.str->len);
            wtk_strbuf_push(buf, item->v.str->data, item->v.str->len);
		}
		wtk_strbuf_push_c(buf,'\"');
		break;
	case WTK_JSON_NUMBER:
		{
			double d=item->v.number;

			if((d-(int)d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
			{
				wtk_strbuf_push_f(buf,"%d",(int)d);
			}
			else
			{
				if (fabs(floor(d)-d)<=DBL_EPSILON)
				{
					wtk_strbuf_push_f(buf,"%.0f",d);
				}/*else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)
				{
					wtk_strbuf_push_f(buf,"%e",d);
				}*/
				else
				{
					wtk_strbuf_push_f(buf,"%f",d);
				}
			}
		}
		break;
	case WTK_JSON_ARRAY:
		{
			wtk_json_array_item_t *aitem;
			int i;

			wtk_strbuf_push_c(buf,'[');
			for(i=0,n=item->v.array->pop;n;n=n->next,++i)
			{
				if(i>0)
				{
					wtk_strbuf_push_c(buf,',');
				}
				aitem=data_offset(n,wtk_json_array_item_t,q_n);
				//printf("[%d]=",i);
				wtk_json_item_print2(aitem->item,buf);
				//printf("\n");
			}
			wtk_strbuf_push_c(buf,']');
		}
		break;
	case WTK_JSON_OBJECT:
		{
			wtk_json_obj_item_t *oitem;
			int i;

			wtk_strbuf_push_c(buf,'{');
			for(n=item->v.object->pop;n;n=n->next,++i)
			{
				if(n!=item->v.object->pop)
				{
					wtk_strbuf_push_c(buf,',');
				}
				oitem=data_offset(n,wtk_json_obj_item_t,q_n);
				wtk_strbuf_push_c(buf,'\"');
				wtk_strbuf_push_add_escape_str(buf,oitem->k.data,oitem->k.len);
				wtk_strbuf_push_s(buf,"\":");
				wtk_json_item_print2(oitem->item,buf);
				//printf("\n");
			}
			wtk_strbuf_push_c(buf,'}');
		}
		break;
	}
	//printf("\n");
}

void wtk_json_item_print(wtk_json_item_t *item,wtk_strbuf_t *buf)
{
	wtk_strbuf_reset(buf);
	wtk_json_item_print2(item,buf);
}

void wtk_json_item_print3(wtk_json_item_t *item)
{
	wtk_strbuf_t *buf;

	buf=wtk_strbuf_new(1024,1);
	wtk_json_item_print(item,buf);
	wtk_debug("[%.*s]\n",buf->pos,buf->data);
	wtk_strbuf_delete(buf);
}

void wtk_json_print(wtk_json_t *json,wtk_strbuf_t *buf)
{
	wtk_strbuf_reset(buf);
	wtk_json_item_print2(json->main,buf);
	//wtk_debug("%.*s\n",buf->pos,buf->data);
}
